//=======================================================================
// Superclass for all stations(buildings)
//=======================================================================
class TFStation extends UTGameObjective
    abstract;

// Station health variables
var(ObjectiveHealth) float DamageCapacity;
var repnotify float Health;
// If > 0, Link Gun secondary heals an amount equal to its damage times this
var(ObjectiveHealth) float LinkHealMult;
// Sounds for stations
var		float      ConstructionTime;
var		SoundCue   DestroyedSound;
var		SoundCue   ConstructedSound;
var		SoundCue   StartConstructionSound;
var		SoundCue   ActiveSound;
var		SoundCue   HealingSound;
var		SoundCue   HealedSound;
var     SoundCue   ShieldHitSound;
// Ambient sound for the station
var AudioComponent AmbientSoundComponent;
//////////////////// Possible vars to use //////////////////////////////
var float           ConstructionTimeElapsed;
var float           SeveredDamagePerSecond;
var float           HealingTime;
// Who owns me?
var Controller Constructor;
// Who to give score to
var Controller LastHealedBy;
// For basecore shield
var transient ParticleSystemComponent ShieldedEffect;
// Shield damage
var int ShieldDamageCounter;
// Emitter spawned when we're being healed
var UTOnslaughtNodeHealEffectBase HealEffect;
// The class of that emitter to use
var class<UTOnslaughtNodeHealEffectBase> HealEffectClasses[2];
// Whether to render icon on HUD beacon (using DrawBeaconIcon())
var bool bDrawBeaconIcon;
// For calculated what to do next
var float                   LastAttackMessageTime;
var float                   LastAttackTime;
var float                   LastAttackExpirationTime;
var float                   LastAttackAnnouncementTime;
var int				        LastAttackSwitch;
var UTPlayerReplicationInfo LastDamagedBy;
var Pawn                    LastAttacker;
// The Basecore
var TFBaseCore BaseCore;
// Team
var int MyTeam;
//Cost of the station
var int BuildCost;

// Net data
replication
{
	if (bNetDirty && Role == ROLE_Authority)
		Health;
}
// draws the icon for the HUD beacon
simulated function DrawBeaconIcon(Canvas Canvas, vector IconLocation, float IconWidth, float IconAlpha, float BeaconPulseScale, UTPlayerController PlayerOwner)
{
	local linearcolor DrawColor;

	DrawColor = (DefenderTeamIndex < 2) ? ControlColor[DefenderTeamIndex] : ControlColor[2];
	DrawIcon(Canvas, IconLocation, IconWidth, IconAlpha, PlayerOwner, DrawColor);
}

simulated event ReplicatedEvent(name VarName)
{
	if (VarName == 'DefenderTeamIndex')
	{
		UpdateEffects(true);
	}
	else
	{
		Super.ReplicatedEvent(VarName);
	}
}

simulated event SetInitialState()
{
	if (Role == ROLE_Authority)
	{
		Health = DamageCapacity;

	   //Sets control used by this station
	   if(TFGRI(WorldInfo.Game.GameReplicationInfo)!=none)
	       TFGRI(WorldInfo.Game.GameReplicationInfo).Control[MyTeam]+=BuildCost;
	}
}

simulated function setinitialteam(int t)
{
    MyTeam=t;
    defenderteamindex=byte(t);
}

simulated function NotifyLocalPlayerTeamReceived()
{
	UpdateEffects(false);
}

/////////////////////// When outpost is created or destroyed, run an iterator function to check if an outpost exists, return to OutpostExists/////////////////////
// Called to update Basecore shield FX
simulated function UpdateEffects(bool bPropagate)
{
    local bool OutpostExists;

	if ( WorldInfo.NetMode == NM_DedicatedServer )
		return;

	// update shield
	UpdateShield(OutpostExists);

	UpdateTeamStaticMeshes();
}

//Updates shield to on or off
simulated function UpdateShield(bool OutpostExists)
{
	if (ShieldedEffect != None)                                                    //Shield Effect is never spawned//
	{   // If true, set shield to hidden
		ShieldedEffect.SetHidden(OutpostExists);
		// If an outpost exists set shield to active, else deactivate it
		if (OutpostExists)
		{
		  ShieldedEffect.SetActive(true);
		}
		else
		{
		  ShieldedEffect.DeactivateSystem();
		}
	}
}
// set the ambient sound state for the station, on/none
simulated function SetAmbientSound(SoundCue NewAmbientSound)
{
	// If the component is already playing this sound, don't restart it
	if (NewAmbientSound != AmbientSoundComponent.SoundCue)
	{
		AmbientSoundComponent.Stop();
		AmbientSoundComponent.SoundCue = NewAmbientSound;
		if (NewAmbientSound != None)
		{
			AmbientSoundComponent.Play();
		}
	}
}

// applies any scaling factors to damage we're about to take
simulated function ScaleDamage(out int Damage, Controller InstigatedBy, class<DamageType> DamageType)
{
	if (class<UTDamageType>(DamageType) != None)
	{
		Damage *= class<UTDamageType>(DamageType).default.NodeDamageScaling;
	}
	//@note: DamageScaling isn't replicated, so this part doesn't work on clients
	if (Role == ROLE_Authority && InstigatedBy != None && InstigatedBy.Pawn != None)
	{
		Damage *= instigatedBy.Pawn.GetDamageScaling();
	}
}

function ScoreDamage(TFPRI AttackerPRI, float Damage)
{
	if ( AttackerPRI != None )
	{
		AttackerPRI.AddDamageBonus(Score*Damage/DamageCapacity);
	}
}

event TakeDamage(int Damage, Controller InstigatedBy, vector HitLocation, vector Momentum, class<DamageType> DamageType, optional TraceHitInfo HitInfo, optional Actor DamageCauser)
{
	if (Damage <= 0 || WorldInfo.Game.bGameEnded || UTGame(WorldInfo.Game).ResetCountdown > 0)
		return;

	// Don't allow levi damage if no instigator
	if ( (InstigatedBy == None) && (class<UTDamageType>(DamageType) != None) && (class<UTDamageType>(DamageType).default.KillStatsName == 'KILLS_LEVIATHANEXPLOSION') )
	{
		return;
	}
	ScaleDamage(Damage, InstigatedBy, DamageType);

	if (InstigatedBy == None || (InstigatedBy.GetTeamNum() != DefenderTeamIndex))
	{
		bForceNetUpdate = true;
		if (InstigatedBy != None)
		{
			LastDamagedBy = UTPlayerReplicationInfo(InstigatedBy.PlayerReplicationInfo);
			LastAttacker = InstigatedBy.Pawn;
			ScoreDamage(TFPRI(LastDamagedBy), FMin(Health, Damage));
		}

		// check any Kismet events
		Super(Actor).TakeDamage(Damage, InstigatedBy, HitLocation, Momentum, DamageType, HitInfo, DamageCauser);

		Health -= Damage;
		if (Health <= 0)
		{
			if ( UTPlayerController(InstigatedBy) != None )
			{
				if ( (class<UTDamageType>(DamageType) != None) && class<UTDamageType>(DamageType).default.bSelfDestructDamage )
				{
					PlayerController(InstigatedBy).ReceiveLocalizedMessage( class'UTWeaponKillRewardMessage', 1 );
				}
			}
			DisableObjective(InstigatedBy);
		}
		else
		{
			BroadcastAttackNotification(InstigatedBy);
		}
	}
	else if ( (PlayerController(InstigatedBy) != None) && !WorldInfo.GRI.OnSameTeam(InstigatedBy,self) )
	{
		PlayerController(InstigatedBy).ReceiveLocalizedMessage(MessageClass, 5);

		// play 'can't attack' sound if player keeps shooting at us
		ShieldDamageCounter += Damage;
		if (ShieldDamageCounter > 200)
		{
			PlayerController(InstigatedBy).ClientPlaySound(ShieldHitSound);
			ShieldDamageCounter -= 200;
		}
	}

	//Adds player credits based on damage done
    if(instigatedby!=none && instigatedby.playerreplicationinfo!=none)
    {
        if(instigatedby.playerreplicationinfo.team.teamindex==myteam)
        {
            instigatedby.playerreplicationinfo.score-=float(damage)/200;
            tfpri(instigatedby.playerreplicationinfo).SubSkill(-float(damage)/10);
        }
        else
        {
            instigatedby.playerreplicationinfo.score+=float(damage)/200;
            tfpri(instigatedby.playerreplicationinfo).AddSkill(float(damage)/10);
        }
    }
}

function BroadcastAttackNotification(Controller InstigatedBy)
{
	//attack notification
	if (LastAttackMessageTime + 1 < WorldInfo.TimeSeconds)
	{
		if ( BaseCore != None )
		{
			BroadcastLocalizedMessage(MessageClass, 9 + DefenderTeamIndex,,, self);
		}
		if ( (InstigatedBy != None) && (InstigatedBy.Pawn != None) )
			UTTeamInfo(WorldInfo.GRI.Teams[DefenderTeamIndex]).AI.CriticalObjectiveWarning(self, InstigatedBy.Pawn);
		LastAttackMessageTime = WorldInfo.TimeSeconds;
	}
	LastAttackTime = WorldInfo.TimeSeconds;
}

function bool HealDamage(int Amount, Controller Healer, class<DamageType> DamageType)
{
	if (Health <= 0 || Health >= DamageCapacity || Amount <= 0 || LinkHealMult <= 0.0 || (Healer != None && !TeamLink(Healer.GetTeamNum())))
	{
		return false;
	}

	Amount = Min(Amount * LinkHealMult, DamageCapacity - Health);
	Health += Amount;

	if (Health >= DamageCapacity)
	{
		PlaySound(HealedSound);
	}
	if (Healer != None && TFPRI(Healer.PlayerReplicationInfo) != None)
	{
		TFPRI(Healer.PlayerReplicationInfo).AddHealBonus(2*Score*float(Amount)/DamageCapacity);
	}

	bForceNetUpdate = TRUE;
	HealingTime = WorldInfo.TimeSeconds;
	LastHealedBy = Healer;

	if (HealEffect == None && DefenderTeamIndex < 2 && HealEffectClasses[DefenderTeamIndex] != None)
	{
		HealEffect = Spawn(HealEffectClasses[DefenderTeamIndex], self);
	}
	SetAmbientSound(HealingSound);

	SetTimer(0.5, false, 'CheckHealing');
	return true;
}

simulated function CheckHealing()
{
	if (WorldInfo.TimeSeconds - HealingTime >= 0.5)
	{
		if (HealEffect != None)
		{
			HealEffect.ShutDown();
			HealEffect = None;
		}
		SetAmbientSound(bIsActive ? ActiveSound : None);
	}
	else
	{
		SetTimer(0.5 - WorldInfo.TimeSeconds + HealingTime, false, 'CheckHealing');
	}
}

simulated state ObjectiveDestroyed
{
	event TakeDamage(int Damage, Controller EventInstigator, vector HitLocation, vector Momentum, class<DamageType> DamageType, optional TraceHitInfo HitInfo, optional Actor DamageCauser)
	{}

	simulated event bool IsCurrentlyDestroyed()
	{
		return true;
	}

	simulated function UpdateShield(bool OutpostExists)
	{
		if (ShieldedEffect != None)
		{
			ShieldedEffect.DeactivateSystem();
			ShieldedEffect.SetHidden(true);
		}
	}

	simulated function BeginState(Name PreviousStateName)
	{
		local PlayerController PC;

		SetAmbientSound(None);
		UpdateEffects(true);

		if ( Role < ROLE_Authority )
			return;

		Health = 0;
		if (WorldInfo.NetMode != NM_DedicatedServer)
		{
			ForEach LocalPlayerControllers(class'PlayerController', PC)
				break;
			if (PC != None)
				PC.ClientPlaySound(DestroyedSound);
			else
				PlaySound(DestroyedSound);
		}

		bForceNetUpdate = TRUE;
		Scorers.length = 0;
		DefenderTeamIndex = 2;
		SetTimer(0.2, false);

		UTGame(WorldInfo.Game).ObjectiveDisabled(Self);
	}
}

function DisableObjective(Controller InstigatedBy)
{
	local PlayerReplicationInfo	PRI;

	if ( InstigatedBy != None )
	{
		Instigator = InstigatedBy.Pawn;
		PRI = InstigatedBy.PlayerReplicationInfo;
	}
	else
	{
		PRI = LastDamagedBy;
	}

	BroadcastLocalizedMessage(MessageClass, 14, PRI,, self);

	if ( DefenderTeamIndex > 1 )
		LogInternal("DisableObjective called with DefenderTeamIndex="$DefenderTeamIndex$" in state "$GetStateName());

	GotoState('ObjectiveDestroyed');
}

defaultproperties
{
    ConstructionTime=30.000000
    bStatic=False
    bNoDelete=False
    BuildCost=0                          //default build cost
    DamageCapacity=1000                  //default damage capacity
    Score=6
    MaxBeaconDistance=4000.000000
    RemoteRole=ROLE_SimulatedProxy
    bIgnoreEncroachers=True
    bAlwaysRelevant=True
    bCollideActors=True
    bCollideWorld=True
    bBlockActors=True
    bProjTarget=True
    bBlocksTeleport=True
    bPathColliding=True
    Name="TFStation"
}